这篇文章记录下如何在springboot工程中使用ueditor,没有做前后端分离,ueditor的前端页面也在后端的springboot工程中。使用修改ueditor后端源码码的方式进行整合
目录springboot整合ueditor一、分析1.1 使用ueditor为什么需要后端工程的配合1.2 ueditor的jsp版后端代码部分详解1.3 总结二、整合ueditor到springboot2.1 复制官方提供的源码,导入需要的依赖2.2创建一个Controller来处理ueditor的请求2.4 前端页面构建2.5 配置文件读取位置的调整2.6 上传图片未找到数据异常的处理2.7 图片回显问题三、总结一、分析1.1 使用ueditor为什么需要后端工程的配合ueditor是一个可以嵌入在前端页面上的富文本编辑器,但它的配置信息和上传图片,上传附件等这些功能的实现需要后端工程的支持,即前端向后端请求配置信息,上传图片。
ueditor官方提供了jsp版的后台代码。这个示例工程可以直接在tomcat中部署进行测试,就是把ueditor前端页面和jsp后端都部署在tomcat中,这种方式官网有详细示例,可以用来熟悉ueditor使用时的前后端交互过程。
1.2 ueditor的jsp版后端代码部分详解首先给出一个ueditor发给后端的获取配置信息的请求的url示例:
http://localhost:8080/ueditor-demo/jsp/controller.jsp?action=config&&noCache=1589691598506在官网下载ueditor的源码,其中有一个jsp文件夹,这里边放的就是jsp后端代码
lib目录中是其依赖的jar包,src中是工程源码,config.json是对ueditor进行配置的配置文件,controller.jsp是前端请求的入口。
controller.jsp中的主要内容如下:
request.setCharacterEncoding( "utf-8" );response.setHeader("Content-Type" , "text/html");String rootPath = application.getRealPath( "/" );out.write( new ActionEnter( request, rootPath ).exec() );可以看到所有请求的处理都是通过ActionEnter这个类中的exec方法处理的。从src目录中找到这个文件。
梳理下这个文件中的主要操作:
(1) 构造方法中实例化了配置文件管理对象ConfigManager,通过这个对象来读取配置文件
public ActionEnter ( HttpServletRequest request, String rootPath ) {this.request = request;this.rootPath = rootPath;this.actionType = request.getParameter( "action" );this.contextPath = request.getContextPath();this.configManager = ConfigManager.getInstance( this.rootPath, this.contextPath, request.getRequestURI() );}(2) exec方法调用了本类中的invoke方法,在invoke方法中根据前端请求参数action来判断到底是进行什么操作,这个action在构造方法中通过request获取,如上边的示例url中action=config
(3) invoke方法的内容如下
public String invoke() {if ( actionType == null || !ActionMap.mapping.containsKey( actionType ) ) {return new BaseState( false, AppInfo.INVALID_ACTION ).toJSONString();}if ( this.configManager == null || !this.configManager.valid() ) {return new BaseState( false, AppInfo.CONFIG_ERROR ).toJSONString();}State state = null;//1.把前台传递的action转换为actionCodeint actionCode = ActionMap.getType( this.actionType );Map conf = null;//2.根据actionCode进行对应的操作:获取配置,上传图片等switch ( actionCode ) {case ActionMap.CONFIG:return this.configManager.getAllConfig().toString();case ActionMap.UPLOAD_IMAGE:case ActionMap.UPLOAD_SCRAWL:case ActionMap.UPLOAD_VIDEO:case ActionMap.UPLOAD_FILE:conf = this.configManager.getConfig( actionCode );state = new Uploader( request, conf ).doExec();break;case ActionMap.CATCH_IMAGE:conf = configManager.getConfig( actionCode );String[] list = this.request.getParameterValues( (String)conf.get( "fieldName" ) );state = new ImageHunter( conf ).capture( list );break;case ActionMap.LIST_IMAGE:case ActionMap.LIST_FILE:conf = configManager.getConfig( actionCode );int start = this.getStartIndex();state = new FileManager( conf ).listFile( start );break;}return state.toJSONString();}1.3 总结在springboot工程中整合ueditor后端部分,我们可以直接拷贝官方提供的jsp后端的src目录中的源码,然后自己建一个Controll来处理来自ueditor的请求,并把所有的请求向jsp中那样使用ActionEnter类的exec方法处理。
二、整合ueditor到springboot2.1 复制官方提供的源码,导入需要的依赖把官方提供的jsp文件中的src目录复制到我们自己的工程中,根据根据jsp文件中lib目录下的jar包导入对应的依赖到我们的工程中。
lib目录中的jar包:
对应的导入如下的maven依赖
commons-iocommons-io2.6commons-fileuploadcommons-fileupload1.3.3commons-codeccommons-codecorg.jsonjson201808132.2创建一个Controller来处理ueditor的请求@RestController@RequestMapping("/ueditor")public class UEditorController {@RequestMapping("/config")public String config(HttpServletRequest request, HttpServletResponse response){String userDir = System.getProperty("user.dir");return new ActionEnter(request, userDir).exec();}}这里的参数userDir我指定的是springboot工程打成jar包运行时这个jar包所在的目录,jsp示例中指定的是应用的根路径,这个可根据实际情况调整。
2.4 前端页面构建在resources目录下新建static文件夹,因为放在这个目录下的内容工程启动时可以被直接访问,所以我们把官方提供的示例直接复制到这个目录下
这样在浏览器中直接访问index.html就可以访问到该页面,修改ueditor.config.js中的serverUrl指向我们定义的这个controller
// 服务器统一请求接口路径, serverUrl: "ueditor/config"2.5 配置文件读取位置的调整现在启动工程已经可以访问到ueditor页面了,但现在因为在后端代码读取配置文件的路径下并没有配置文件,所以前台页面会提示后端配置错误,接下来我们研究下后端代码如何读取配置文件。
前边提到在ActionEnter的构造方法中创建了ConfigManager对象,通过ConfigManager来读取配置文件
ConfigManager的构造方法调用了initEnv方法,这个方法的代码如下
private void initEnv () throws FileNotFoundException, IOException {File file = new File( this.originalPath );if ( !file.isAbsolute() ) {file = new File( file.getAbsolutePath() );}this.parentPath = file.getParent();String configContent = this.readFile( this.getConfigPath() );try{JSONObject jsonConfig = new JSONObject( configContent );this.jsonConfig = jsonConfig;} catch ( Exception e ) {this.jsonConfig = null;}}可以看到给readFile方法传入了一个路径返回了configContent,所以是这个readFile方法在读取配置文件,
private String readFile ( String path ) throws IOException {StringBuilder builder = new StringBuilder();try {InputStreamReader reader = new InputStreamReader( new FileInputStream( path ), "UTF-8" );BufferedReader bfReader = new BufferedReader( reader );String tmpContent = null;while ( ( tmpContent = bfReader.readLine() ) != null ) {builder.append( tmpContent );}bfReader.close();} catch ( UnsupportedEncodingException e ) {// 忽略}return this.filter( builder.toString() );}可以看到在这个方法中通过InputStreamReader在读取配置文件。所以我们可以把自己的配置文件放在resources目录下,通过类加载器返回输入流传给InputStreamReader,这样就可以读取到自己的配置文件
private String readFile () throws IOException {//更改读取后端配置文件的位置InputStream resourceAsStream = ConfigManager.class.getClassLoader().getResourceAsStream("config.json");StringBuilder builder = new StringBuilder();...省略其他然后这个readFile方法就可以修改为不带参数的
2.6 上传图片未找到数据异常的处理经过上边的处理后编辑器页面已经可以使用了,但如果上传图片会报未找到数据的异常,这是因为上传图片的请求被springmvc的MultipartResolver拦截到了并封装成了MultipartFile对象,所以请求中没有文件数据,这个MultipartResolver是springboot自动配置的StandardServletMultipartResolver。所以解决的办法是排除掉
springboot自动配置MultipartResolver,重写一个自己的MultipartResolver并在其中放行ueditor的上传请求。
(1) 排除springboot自动配置MultipartResolver
在application.yml中进行如下配置
spring: autoconfigure:#排除springboot对MultipartResolver的自动配置,使用自己的配置,在其中放行来自ueditor的上传请求exclude: org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration(2) 创建一个自定义的MultipartResolver,继承StandardServletMultipartResolver
public class MyCommonsMultipartResolver extends StandardServletMultipartResolver {//springmvc对上传文件请求的处理,使其过滤掉ueditor的上传请求@Overridepublic boolean isMultipart(HttpServletRequest request) {String requestURI = request.getRequestURI();if(requestURI.contains("/ueditor")){return false;}return super.isMultipart(request);}}(3) 把这个自定义类配置到spring容器中
@Bean(name = "multipartResolver")public MultipartResolver multipartResolver(){return new MyCommonsMultipartResolver();}这样图片上传功能就可以了,图片的保存路径是在创建ActionEnter时的第二个参数指定的路径,再加上config.json中指定的imagePathFormat,可以通过修改配置文件中的这个参数来改变图片的保存路径。
2.7 图片回显问题上一步只是完成了图片的上传,但图片在编辑器中的回显依然存在问题,报找不到图片的错误,这是因为后端图片上传成功后给前端返回了一个url,前端会访问这个url获取图片。追踪源码会发现在BinaryUploader#save方法中
if (storageState.isSuccess()) {storageState.putInfo("url", PathFormat.format(savePath));storageState.putInfo("type", suffix);storageState.putInfo("original", originFileName + suffix);}这个savePath就是上面config.json中的imagePathFormat再加上文件的保存名称而前端拿到这个url后,会直接请求这个地址:http://localhost:8080/url,比如按我的配置文件,这个url是/ueditor/upload/image/20200517/1589695937922096997.png
因为现在工程中不存在这样一个接口,所以获取不到图片。
这里给出一种解决方案,在工程中增加一个获取图片的接口,然后在这里把这个url指向获取图片的接口(文件名拼接在url上),这样前端就可以拿到上传的图片进行回显。
当然也可以修改ueditor的前端回显图片部分直接指向获取图片的接口,这样这里的url就可以只放一个参数名
三、总结这篇文章记录了在springboot工程中如何整合ueditor,并没有进行前后端分离,导入了ueditor的jsp后端源码并进行了修改,没有修改ueditor的前端源码。